import { _decorator, Color, Component, Graphics, instantiate, Mat4, math, MotionStreak, Node, Rect, Sprite, toRadian, tween, Tween, UITransform, Vec2, Vec3 } from 'cc';
import { CommonUtils, GameUtils, MyMath } from '../../utils';
import { Creature } from '../../data/define';
import { CUSTOM_EVENT, dispatcher } from '../../manager/EventDispatcher';
import { monsterManager } from '../../manager/MonsterManager';
const { ccclass, property } = _decorator;
const LOG_TITLE = 'Player:'
const TEMP_POSITION = new Vec3()

const EVOLUTION_NUM = 3

const CreaturesCount: number[] = [] //索引为lv 值为count

@ccclass('Player')
export class Player extends Component {
    @property(Node)
    public nodeCreature: Node = null

    @property(Node)
    public camera: Node = null

    @property(Node)
    public streak: Node = null

    @property(Graphics)
    public debugDraw: Graphics = null

    public data_speed: number = 200
    public data_angle: number = 0
    public data_destAngle: number = 0
    public data_angleSpeed: number = 270
    public creatures: Creature[] = []

    public get creatureBoundingBox() {
        return this._creatureBoundingBox
    }
    private _creatureBoundingBox: Rect = new Rect()
    private _creatureRects: Rect[] = []

    //temp mark destroy creature
    private _tempDestroyCreatureIds: number[] = [] //记录的是index
    private _tempAddCreatures: number[] = [] //记录的是lv

    onLoad() {
        
    }

    start() {
        CreaturesCount.length = 0
        this.addCreature(1)
        this.updateCreatures()

        // setInterval(() => {
        //     this.updateCreatures(this.addCreature(1))
        // }, 500);
    }

    updateOuter(deltaTime: number) { //外部调用update
        this.resetTempData()

        this.updateAngle(deltaTime) //data
        this.updateCreaturesAngle()

        const pos = this.node.position
        const addPos = this.getAddPosition(deltaTime)
        this.node.setPosition(pos.x + addPos.x, pos.y + addPos.y)

        this.genAllCreatureBoundingBoxes()

        //debugdraw
        const boundingBox = this._creatureBoundingBox
        // boundingBox.transformMat4(Mat4.fromZRotation(new Mat4(), toRadian(this.nodeCreature.angle)))
        this.debugDraw.clear()
        this.debugDraw.lineWidth = 4
        this.debugDraw
        .rect(boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height)
        this.debugDraw.strokeColor = Color.WHITE
        this.debugDraw.stroke()

        // const creatureRectLines = GameUtils.getNodeRectLines(this.nodeCreature.children[0], this.data_angle)
        //     // console.log(LOG_TITLE, ' create intersect:', )
        // this.debugDraw.moveTo(creatureRectLines[0][0].x, creatureRectLines[0][0].y)
        // this.debugDraw.lineTo(creatureRectLines[1][0].x, creatureRectLines[1][0].y)
        // this.debugDraw.lineTo(creatureRectLines[2][0].x, creatureRectLines[2][0].y)
        // this.debugDraw.lineTo(creatureRectLines[3][0].x, creatureRectLines[3][0].y)
        // this.debugDraw.close()
        // this.debugDraw.strokeColor = Color.YELLOW
        // this.debugDraw.stroke()
        
    }

    //data
    updateAngle(dt: number) {
        if (this.data_angle == this.data_destAngle) 
            return

        const dtAngle = this.data_angleSpeed * dt

        const offset = this.data_destAngle - this.data_angle
        let offsetLength = offset
        let sign = Math.sign(offset)
        if (Math.abs(offset) > 180) {
            sign *= -1
            offsetLength = offset > 180 ? 360 - offsetLength : 360 + offsetLength
        }
        else {
            offsetLength = Math.abs(offsetLength)
        }

        if (dtAngle > offsetLength) {
            this.data_angle = this.data_destAngle
        }
        else {
            const angle = dtAngle * sign + this.data_angle
            if (angle > 360) {
                this.data_angle = angle % 360
            }
            else if (angle < 0) {
                this.data_angle = angle + 360
            }
            else {
                this.data_angle = angle
            }
        }
        console.log(LOG_TITLE, 'angle:', this.data_angle, ' offsetlength:', offsetLength,  'offset:', offset, 'destangle:', this.data_destAngle, 'dtAngle:', dtAngle)

    }

    updateCreatures() {
        const children = this.nodeCreature.children
        for (let i = 0;  i < this.creatures.length; i++) {
            const lv = this.creatures[i].lv
            const name = lv.toString()
            let child = children[i]
            if (!child || child.name != name) {
                if (child) {
                    child.removeFromParent()
                    child.destroy()
                }
                
                // const prefab = monsterManager.popMonster(lv)
                child = monsterManager.popMonster(lv)
                this.nodeCreature.insertChild(child, i)
                child.setPosition(this.getIndexPosition(i))
                child.angle = this.data_angle
                child.name = name
            }
        }

        for (let i = children.length - 1; i >= this.creatures.length; i--) {
            const child = children[i]
            child.removeFromParent()
            child.destroy()
        }
    }

    updateCreaturesWithInfos(changeInfos: {delete: number[], add: any[], move: any[]}, ignoreOffset = false) { //进化时候是否不做动画偏移
        const children = this.nodeCreature.children
        const deleteNodes = changeInfos.delete.map(index => children[index])
        const moveInfos = changeInfos.move
        moveInfos.forEach(info => info.node = children[info.fromIndex] )
        if (deleteNodes) {
            deleteNodes.forEach(node => node.destroy())
        }

        moveInfos.forEach(info => {
            const node: Node = info.node
            Tween.stopAllByTarget(node)
            tween()
            .target(node)
            .to(0.1, { position: this.getIndexPosition(info.toIndex) })
            .start()
        })

        const animOffsetX = ignoreOffset ? 0 : -100
        const addInfo = changeInfos.add
        addInfo.forEach(info => {
            const lv = info.lv
            const index = info.index
            const child = monsterManager.popMonster(lv)
            this.nodeCreature.insertChild(child, index)
            child.setPosition(animOffsetX, 0)
            tween()
            .target(child)
            .to(0.2, { position: this.getIndexPosition(index)})
            .start()
            child.angle = this.data_angle
            child.name = lv.toString()
        })
    }

    updateCreaturesAngle() {
        this.nodeCreature.children.forEach(child => {
            child.angle = this.data_angle
        })
    }

    resetTempData() {
        this._tempAddCreatures.length = 0
        this._tempDestroyCreatureIds.length = 0
    }

    getIndexPosition(index: number): Vec3 {
        if (index == 0)
            return new Vec3()
        else {
            const lastLayer = Math.floor((index + 1) / 2)
            const pos = this.getIndexPosition(lastLayer - 1)
            if ((index + 1) % 2 == 0) { //在左边
                return pos.set(pos.x - 30 - 10 * (lastLayer - 1), pos.y - 50 - 10 * (lastLayer - 1), pos.z)
            }
            else {
                return pos.set(pos.x + 30 + 10 * (lastLayer - 1), pos.y - 50 - 10 * (lastLayer - 1), pos.z)
            }
        }
    }

    genAllCreatureBoundingBoxes() {
        const children = this.nodeCreature.children
        this._creatureRects.length = children.length

        let minX, minY, maxX, maxY
        for (let i = 0; i < children.length; i++) {
            const boundingBox = children[i].getComponent(UITransform).getBoundingBox()
            this._creatureRects[i] = boundingBox
            if (minX == undefined) {
                minX = boundingBox.xMin
                minY = boundingBox.yMin
                maxX = boundingBox.xMax
                maxY = boundingBox.yMax
            }
            else {
                minX = Math.min(minX, boundingBox.xMin)
                minY = Math.min(minY, boundingBox.yMin)
                maxX = Math.max(maxX, boundingBox.xMax)
                maxY = Math.max(maxY, boundingBox.yMax)
            }
        }

        this._creatureBoundingBox.set(minX, minY, maxX - minX, maxY - minY)
    }

    getAddPosition(deltaTime: number) {
        let velocity = new Vec2(0, 1).rotate(toRadian(this.data_angle))
        const length = this.data_speed * deltaTime
        return velocity.multiplyScalar(length)
    }

    isMonsterInCreatureRect(monsterRect: Rect) { //monsterRect需要在Player的空间下
        if (!this._creatureBoundingBox) {
            console.error(LOG_TITLE, ' creature的aabb框为空')
            return false
        }

        return this._creatureBoundingBox.intersects(monsterRect)
    }

    getMonsterIntersectCreatureIds(monsterRect: Rect, monster: Node) {
        let creatures: number[] = []
        const children = this.nodeCreature.children

        const monsterRectLines = GameUtils.getNodeRectLines(monster, undefined, this.node) //转换到Player节点坐标下
        this._creatureRects.forEach((rect, index) => {
            const creature = this.creatures[index]
            if (this._tempDestroyCreatureIds.indexOf(creature.id) != -1) { //如果是已经被比较过移除的则不用判断
                return
            }

            if (rect.intersects(monsterRect)) {
                const creature = children[index]
                const creatureRectLines = GameUtils.getNodeRectLines(creature) //默认转换到Player节点坐标下 
                if (MyMath.isRectIntersect(creatureRectLines, monsterRectLines)) {
                    // console.log(LOG_TITLE, ' create intersect:', )
                    this.debugDraw.moveTo(creatureRectLines[0][0].x, creatureRectLines[0][0].y)
                    this.debugDraw.lineTo(creatureRectLines[1][0].x, creatureRectLines[1][0].y)
                    this.debugDraw.lineTo(creatureRectLines[2][0].x, creatureRectLines[2][0].y)
                    this.debugDraw.lineTo(creatureRectLines[3][0].x, creatureRectLines[3][0].y)
                    this.debugDraw.close()
                    this.debugDraw.strokeColor = Color.BLUE
                    this.debugDraw.stroke()

                    creatures.push(this.creatures[index].id)
                }
            }
        })

        return creatures
    }

    collisionSettle() { //碰撞结算
        // let creaturesState: {index: }
        let isDirty = false
        const originCreatures = this.creatures.slice()
        if (this._tempDestroyCreatureIds.length > 0) {
            this._tempDestroyCreatureIds.forEach(id => {
                const index = this.creatures.findIndex(c => c.id == id)
                if (index == -1) {
                    console.error(LOG_TITLE, '不可能: 标记的移除id没找到:', id, this.creatures)
                }
                else {
                    this.creatures.splice(index, 1)
                    isDirty = true
                }
            })
        }

        if (this._tempAddCreatures.length > 0) {
            this._tempAddCreatures.forEach(lv => this.addCreature(lv))
            isDirty = true
        }

        if (isDirty) {
            const changeInfos = this.genChangeInfo(originCreatures)
            this.updateCreaturesWithInfos(changeInfos)
            const oldMaxlv = originCreatures[0].lv
            const curMaxLv = this.creatures[0].lv
            if (oldMaxlv != curMaxLv) {
                dispatcher.emit(CUSTOM_EVENT.CHANGE, curMaxLv)
            }
        }
    }

    genChangeInfo(oldCreatures: Creature[]) { //生成变化信息
        const curCreatures = this.creatures
        const filterOnce: boolean[] = []
        filterOnce.length = curCreatures.length

        const addCreatureInfos: {}[] = []
        const deleteCreatureInfos: number[] = []
        const moveCreatureInfos: {}[] = []
        //先筛选出移除的
        for (let i = 0; i < oldCreatures.length; i++) {
            const oldCreature = oldCreatures[i]
            const index = curCreatures.findIndex(c => oldCreature.id == c.id)
            if (index != -1) {
                filterOnce[index] = true
                if (index == i) { //位置没有发生变化
                    //noting
                }
                else {
                    moveCreatureInfos.push({fromIndex: i, toIndex: index}) //移动
                }
            }
            else {
                deleteCreatureInfos.push(i) //移除
            }
        }

        for (let j = 0; j < curCreatures.length; j++) {
            if (!filterOnce[j]) {
                addCreatureInfos.push({index: j, lv: curCreatures[j].lv})
            }
        }

        return {
            delete: deleteCreatureInfos,
            add: addCreatureInfos,
            move: moveCreatureInfos
        }
    }

    //data
    monsterCollision(monsterLv: number, creatureId: number) { //是否可以吞噬该monster 即可以升级  否则则是销毁
        let isSwallow = false
        const creature = this.creatures.find(c => c.id == creatureId)
        if (creature != undefined) {
            if (creature.lv >= monsterLv) {
                this._tempAddCreatures.push(monsterLv)
                isSwallow = true
            }
            else {
                this._tempDestroyCreatureIds.push(creature.id)
            }
        }

        return isSwallow
    }

    addCreature(lv: number) {
        // let evolutionInfos = [] //add index   evolution head num
        const index = this.creatures.findIndex(c => c.lv <= lv)
        if (index == -1) {
            if (this.creatures.length == 0) {
                this.creatures.unshift(this.genCreature(lv))
                // evolutionInfos[0] = {
                //     type: 'start',
                //     lv: lv
                // }
            }
            else {
                // evolutionInfos[0] = {
                //     type: 'add',
                //     index: this.creatures.length,
                //     lv: lv
                // }
                this.creatures.push(this.genCreature(lv))
                console.log(LOG_TITLE, '尾巴增加了一个生物', '位置:', this.creatures.length, ' 等级:', lv)
            }
        }
        else {
            let evolutionLv = undefined
            let evolutionIndex = index
            while (true) {
                let tempIndex = this.getEvolutionIndex(evolutionLv || lv)
                if (tempIndex != -1) {
                    evolutionLv = evolutionLv == undefined ? lv + 1 : evolutionLv + 1
                    evolutionIndex = tempIndex
                }
                else {
                    break
                }
            }

            // const length = this.creatures.length
            if (evolutionLv) {
                //delete queue
                const lastLvIndex = CommonUtils.findLastIndex(this.creatures, (creature) => creature.lv == lv)
                const consumeNum = (lastLvIndex - evolutionIndex + 1)
                // evolutionInfos[0] = {
                //     type: 'delete',
                //     index: evolutionIndex,
                //     num: consumeNum
                // }

                // evolutionInfos[1] = {
                //     type: 'evolution',
                //     index: evolutionIndex
                // }

                // if (lastLvIndex + 1 < length) {
                //     evolutionInfos[2] = {
                //         type: 'move',
                //         index: lastLvIndex + 1,
                //         num: length - (lastLvIndex + 1),
                //         offset: -((lastLvIndex - evolutionIndex + 1) - 1) //删除了N个增加了一个
                //     }
                // }

                this.creatures.splice(evolutionIndex, consumeNum, this.genCreature(evolutionLv))
                console.log(LOG_TITLE, '进化了：', evolutionLv, '级', ' 移除数量:', consumeNum)
            }
            else {
                // evolutionInfos[0] = {
                //     type: 'add',
                //     index: index
                // }

                // evolutionInfos[1] = {
                //     type: 'move',
                //     index: index,
                //     num: length - index,
                //     offset: 1
                // }

                if (lv == this.creatures[evolutionIndex].lv) {
                    evolutionIndex = CommonUtils.findLastIndex(this.creatures, (creature) => creature.lv == lv) + 1
                }

                this.creatures.splice(evolutionIndex, 0, this.genCreature(lv))
                console.log(LOG_TITLE, '中间增加了一个生物', '位置:', evolutionIndex, ' 等级:', evolutionLv)
            }
        }

        // return evolutionInfos
    }

    genCreature(lv: number) {
        if (CreaturesCount.length < lv) {
            CreaturesCount.length = lv
        }

        const limit = 1000
        let count = CreaturesCount[lv] || lv * limit //scale
        CreaturesCount[lv] = count + 1

        return {lv : lv, id: count}
    }

    startSpecial() {
        this.data_speed = 600
        this.streak.active = true
    }

    stopSpecial() {
        this.data_speed = 200
        this.streak.active = false
    }

    getEvolutionIndex(lv: number) {
        const index = this.creatures.findIndex((creature) => creature.lv == lv)
        if (index == -1) {
            return index
        }
        
        const endIndex = index + (EVOLUTION_NUM - 1)
        if (endIndex > this.creatures.length) {
            return -1
        }

        let isCanEvolution = true
        for (let i = index + 1; i < endIndex; i++) {
            if (this.creatures[i].lv != lv) {
                isCanEvolution = false
                break
            }
        }

        return isCanEvolution ? index : -1
    }

    getMaxLv() {
        return this.creatures[0].lv
    }

    evolution(force = true) {
        if (force) {
            const maxLv = this.getMaxLv()
            const originCreatures = this.creatures.slice()
            this.creatures.splice(0, 1, this.genCreature(maxLv + 1)) //移除一个最高等级 添加一个最高等级+1
            const changeInfos = this.genChangeInfo(originCreatures)
            this.updateCreaturesWithInfos(changeInfos)
            dispatcher.emit(CUSTOM_EVENT.CHANGE, maxLv + 1)
        }
    }

    flyForward(num = 100, lv = 1) {
        const startAngle = 180
        const radius = 250
        const destRadius = 80
        const perAngle = 360 / 15
        // const tw = tween().target(this)
        const PI = 3.1415926
        // const dest = new Vec3(50, 50)
        for (let i = 0; i < num; i++) {
            const angle = startAngle - i * perAngle
            const rad = angle / 180 * PI
            const sinx = Math.cos(rad) 
            const siny = Math.sin(rad)
            const monster = monsterManager.genMonster(lv, true)
            this.node.addChild(monster)
            monster.setPosition(sinx  * radius, siny * radius)
            monster.angle = -90 - i * perAngle
            monster.getComponent(Sprite).enabled = false
            tween(monster)
            .delay(0.05  * i)
            .show()
            .to(0.15, { position: new Vec3(sinx * destRadius, siny * destRadius) })
            .call(() => {
                const originCreatures = this.creatures.slice()
                this.addCreature(lv)
                const changeInfos = this.genChangeInfo(originCreatures)
                this.updateCreaturesWithInfos(changeInfos, true)
                const oldMaxlv = originCreatures[0].lv
                const curMaxLv = this.creatures[0].lv
                if (oldMaxlv != curMaxLv) {
                    dispatcher.emit(CUSTOM_EVENT.CHANGE, curMaxLv)
                }
                monster.destroy()
            })
            .start()
        }
    }
}


